<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { NCard, NSpin, NInput, NSelect, NTag, NTime, NEmpty, NButton } from 'naive-ui'
import { SearchOutlined, ReloadOutlined, WarningOutlined } from '@ant-design/icons-vue'
import { getReverseShAuditResults, type ReverseShAuditData } from '@/api/reversesh'
import { message } from 'ant-design-vue'

const auditData = ref<ReverseShAuditData[]>([])
const loading = ref(false)
const searchKeyword = ref('')
const selectedNode = ref<string | null>(null)

const nodeOptions = computed(() => {
  const nodes = [...new Set(auditData.value.map(item => item.node_name))]
  return nodes.map(node => ({ label: node, value: node }))
})

const filteredData = computed(() => {
  let filtered = auditData.value
  
  if (searchKeyword.value) {
    filtered = filtered.filter(item => 
      item.syscall.toLowerCase().includes(searchKeyword.value.toLowerCase()) ||
      item.node_name.toLowerCase().includes(searchKeyword.value.toLowerCase())
    )
  }
  
  if (selectedNode.value) {
    filtered = filtered.filter(item => item.node_name === selectedNode.value)
  }
  
  return filtered.sort((a, b) => new Date(b.event_time).getTime() - new Date(a.event_time).getTime())
})

const getSyscallColor = (syscall: string) => {
  const dangerousCalls = ['execve', 'connect', 'socket', 'bind', 'listen']
  return dangerousCalls.some(call => syscall.toLowerCase().includes(call)) ? 'error' : 'warning'
}

const fetchAuditResults = async () => {
  loading.value = true
  try {
    const res = await getReverseShAuditResults()
    if (res.code === 0) {
      auditData.value = res.data
    } else {
      message.error(`获取数据失败: ${res.message}`)
    }
  } catch (error) {
    message.error('网络请求失败')
  } finally {
    loading.value = false
  }
}

onMounted(fetchAuditResults)
</script>

<template>
  <div class="audit-container">
    <div class="header">
      <h2>
        <warning-outlined style="color: #ff4d4f; margin-right: 8px;" />
        反弹Shell审计结果
      </h2>
      <div class="header-actions">
        <n-button @click="fetchAuditResults" :loading="loading" type="primary" ghost>
          <template #icon>
            <reload-outlined />
          </template>
          刷新数据
        </n-button>
      </div>
    </div>

    <div class="filters">
      <n-input
        v-model:value="searchKeyword"
        placeholder="搜索系统调用或节点名称..."
        style="width: 300px;"
        clearable
      >
        <template #prefix>
          <search-outlined />
        </template>
      </n-input>
      
      <n-select
        v-model:value="selectedNode"
        placeholder="筛选节点"
        style="width: 200px;"
        :options="nodeOptions"
        clearable
      />
    </div>

    <n-spin :show="loading">
      <div class="timeline-container" v-if="filteredData.length > 0">
        <div class="timeline">
          <div 
            v-for="(item, index) in filteredData" 
            :key="item.id"
            class="timeline-item"
            :class="{ 'timeline-item-danger': getSyscallColor(item.syscall) === 'error' }"
          >
            <div class="timeline-dot">
              <warning-outlined v-if="getSyscallColor(item.syscall) === 'error'" />
              <span v-else class="dot-normal"></span>
            </div>
            
            <n-card class="event-card" hoverable>
              <div class="card-header">
                <div class="card-title">
                  <n-tag 
                    :type="getSyscallColor(item.syscall)"
                    size="large"
                    round
                  >
                    {{ item.syscall }}
                  </n-tag>
                  <span class="node-name">{{ item.node_name }}</span>
                </div>
                <n-time 
                  :time="new Date(item.event_time)" 
                  format="yyyy-MM-dd HH:mm:ss"
                  class="event-time"
                />
              </div>
              
              <div class="card-content">
                <div class="info-row">
                  <span class="label">事件ID:</span>
                  <span class="value">#{{ item.id }}</span>
                </div>
                <div class="info-row">
                  <span class="label">CyberTwin ID:</span>
                  <span class="value">{{ item.cybertwin_id }}</span>
                </div>
              </div>
            </n-card>
          </div>
        </div>
      </div>
      
      <n-empty v-else description="暂无审计数据" style="margin-top: 100px;">
        <template #extra>
          <n-button @click="fetchAuditResults" type="primary">
            重新加载
          </n-button>
        </template>
      </n-empty>
    </n-spin>
  </div>
</template>

<style scoped>
.audit-container {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
}

.header h2 {
  margin: 0;
  font-size: 24px;
  color: #262626;
  display: flex;
  align-items: center;
}

.filters {
  display: flex;
  gap: 16px;
  margin-bottom: 32px;
  align-items: center;
}

.timeline-container {
  position: relative;
  padding-left: 40px;
}

.timeline {
  position: relative;
}

.timeline::before {
  content: '';
  position: absolute;
  left: -20px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: linear-gradient(to bottom, #3b82f6, #ef4444);
}

.timeline-item {
  position: relative;
  margin-bottom: 24px;
}

.timeline-dot {
  position: absolute;
  left: -32px;
  top: 20px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  border: 3px solid #3b82f6;
  z-index: 1;
}

.timeline-item-danger .timeline-dot {
  border-color: #ef4444;
  background: #fef2f2;
  color: #ef4444;
}

.dot-normal {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #3b82f6;
}

.event-card {
  border-radius: 12px;
  border: 1px solid #e5e7eb;
  transition: all 0.2s;
}

.event-card:hover {
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
  transform: translateY(-2px);
}

.timeline-item-danger .event-card {
  border-left: 4px solid #ef4444;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 16px;
}

.card-title {
  display: flex;
  align-items: center;
  gap: 12px;
}

.node-name {
  font-weight: 600;
  color: #374151;
  font-size: 16px;
}

.event-time {
  color: #6b7280;
  font-size: 14px;
}

.card-content {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.info-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.label {
  font-weight: 500;
  color: #6b7280;
  min-width: 120px;
}

.value {
  color: #374151;
  font-family: 'Monaco', 'Consolas', monospace;
}
</style>
